﻿using com.kmer.ApiServer.Attributes;
using com.kmer.ApiServer.com.kmer.Model;
using com.kmer.Attributes;
using com.kmer.Cache;
using com.kmer.Helper;
using com.kmer.interfaces;
using com.kmer.library.com.kmer.Helper;
using com.kmer.library.Factorys;
using kmer.Helper;
using kmer.Web;
using kmer.Web.Helper;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data.Entity.Validation;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web;
using System.Web.SessionState;

// ReSharper disable once CheckNamespace
namespace com.kmer.ApiServer
{
    /// <summary>
    /// 所有API的基类，用来分发Action
    /// </summary>
    public class BaseHandler : ISessionContext, IHttpHandler, IReadOnlySessionState
    {
        /// <summary>
        /// 用户Token
        /// </summary>
        protected const string USERTOKEN_KEY = "UserToken:";

        /// <summary>
        /// Session
        /// </summary>
        public HttpSessionState Session { get; protected set; }
        /// <summary>
        /// 当前请求信息
        /// </summary>
        public HttpRequest Request { get; protected set; }
        /// <summary>
        /// 页面返回信息
        /// </summary>
        public HttpResponse Response { get; protected set; }
        /// <summary>
        /// 服务器相关
        /// </summary>
        public HttpServerUtility Server { get; protected set; }
        /// <summary>
        /// HttpContext
        /// </summary>
        public HttpContext Context { get; protected set; }

        bool IHttpHandler.IsReusable => false;

        /// <summary>
        /// 控制器名称
        /// </summary>
        public string Controller => this.GetType().Name.Replace("Handler", "");

        /// <summary>
        /// 保存当前APP信息
        /// </summary>
        protected ApiConfig ApiApp { get; set; }
        /// <summary>
        /// 系统 Token（AccessToken）
        /// </summary>
        protected string Token { get; set; }

        /// <summary>
        /// 单位：秒
        /// </summary>
        protected const int Timeout = 7200;
        /// <summary>
        /// Redis 超时 单位：分钟
        /// </summary>

        /// <summary>
        /// 执行API（由 Core.Init调用）
        /// </summary>
        /// <param name="context"></param>
        /// <param name="action"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public object Execute(HttpContext context, string action, string parameters)
        {
            Context = context;
            Session = context.Session;
            Request = context.Request;
            Response = context.Response;
            Server = context.Server;

            var beginTime = DateTime.Now;
            var thisType = this.GetType();
            object r = null;
            if (!CheckAccessToken(thisType, out r, false)) return r;
            int? UserId = CheckUserToken(Request, this.ApiApp);
            if (UserId == 0) UserId = null;
            if (CheckAttribute(thisType, out r, beginTime, UserId.ToString()))
            {
                try
                {
                    r = parseMethod(action, parameters, UserId.ToString());
                    log(beginTime, false);
                }
                catch (ArgumentException ae)
                {
                    r = Error(ae.Message, 500);
                    log(beginTime, true);
                }
                catch (TargetInvocationException e)
                {
                    r = Error(e, 501);
                    log(beginTime, true);
                    //} catch (JsonSerializationException e) {
                    //    r = Error(e, 501);
                    //    log(beginTime, true);
                }
                catch (Exception e)
                {
                    r = Error(e, 500);
                    log(beginTime, true);
                }
            }
            AddApiCallLog(parameters, beginTime, r);
            return r;
        }

        void IHttpHandler.ProcessRequest(HttpContext context)
        {
            Context = context;
            Session = context.Session;
            Request = context.Request;
            Response = context.Response;
            Server = context.Server;

            var beginTime = DateTime.Now;
            var content = Request.GetPostContent();
            var thisType = this.GetType();
            object r = null;
            this.Action = string.IsNullOrWhiteSpace(Request.PathInfo)
                ? Request.Get("a", string.Empty)
                : Request.PathInfo.Split('/').Distinct().FirstOrDefault(item => string.IsNullOrWhiteSpace(item) == false);

            if (!CheckAccessToken(thisType, out r)) return;
            int? UserId = CheckUserToken(Request, this.ApiApp);
            if (UserId == 0) UserId = null;
            if (CheckAttribute(thisType, out r, beginTime, UserId.ToString()))
            {
                try
                {
                    r = parseMethod(Request.PathInfo, content, UserId.ToString());
                    log(beginTime, false);
                }
                catch (ArgumentException ae)
                {
                    r = Error(ae.Message);
                    log(beginTime, true);
                    //} catch (JsonSerializationException e) {
                    //    r = Error(e, 501);
                    //    log(beginTime, true);
                }
                catch (TargetInvocationException e)
                {
                    r = Error(e.InnerException ?? e, 501);
                    log(beginTime, true);
                }
                catch (Exception e)
                {
                    r = Error(e, 500);
                    log(beginTime, true);
                }
            }
            output(r);
            AddApiCallLog(content, beginTime, r);
        }
        /// <summary>
        /// 检查控制器的权限控制标志，成功返回 true
        /// </summary>
        /// <param name="thisType"></param>
        /// <param name="r"></param>
        /// <param name="beginTime"></param>
        /// <param name="UserID"></param>
        /// <returns></returns>
        protected bool CheckAttribute(Type thisType, out object r, DateTime beginTime, string UserID)
        {
            r = null;
            if (string.Compare("GetDTD", this.Action, StringComparison.OrdinalIgnoreCase) == 0)
                return true;

            var attribs = thisType.GetCustomAttributes(true);
            var isMustLogin = attribs.Any(item => item is MustLoginAttribute);
            var isMustAdmin = attribs.Any(item => item is MustAdminAttribute);
            var isMustBackend = attribs.Any(item => item is MustBackendAttribute);

            if (isMustAdmin && (string.IsNullOrWhiteSpace(UserID) || MustAdminAttribute.Check(UserID) == false))
            {
                r = Error("必须是管理员！", 403);
                log(beginTime, true);
                return false;
            }
            if (isMustBackend && string.IsNullOrWhiteSpace(UserID))
            {
                r = Error("必须是后台用户！", 403);
                log(beginTime, true);
                return false;
            }
            if (isMustLogin && string.IsNullOrWhiteSpace(UserID))
            {
                r = Error("用户认证过期，请登录后再请求！", 401);
                log(beginTime, true);
                return false;
            }
            if (isMustBackend)
            {
                return RcHelper.HasRights(UserID, this.Controller, this.Action);
            }
            //var attr1 = (MustRights)attribs.FirstOrDefault(item => item is MustRights);
            //if (attr1 != null && attr1.Check(UserInfo.StaffNo) == false) {
            //    r = Error("没有权限", 4003);
            //    log(beginTime, true);
            //}
            return true;
        }

        private static RedisClient _rcClient;
        static string getRedis(string key)
        {
            if (_rcClient == null)
                _rcClient = new RedisClient(ConfigurationHelper.Get<int>("redis-cache-index", 12));
            var pre = "kmer:cache:";
            return (string)_rcClient.GetStringValue(pre + key);
        }

        static bool existsRedis(string key)
        {
            if (_rcClient == null)
                _rcClient = new RedisClient(ConfigurationHelper.Get<int>("redis-cache-index", 12));
            var pre = "kmer:cache:";
            return _rcClient.KeyExists(pre + key);
        }


        /// <summary>
        /// 获取Token
        /// </summary>
        public string UserToken => Request.Get("u", "");

        /// <summary>
        /// 用户ID,如果有登陆
        /// </summary>
        public int CusID
        {
            get
            {
                var userToken = Request.Get("u", "");
                int cusID = RedisCache.GetInt(USERTOKEN_KEY + userToken, 0);
                return cusID;
            }
        }

        /// <summary>
        /// 公司ID
        /// </summary>
        public string CompanyID
        {
            get
            {
                var userData = CacheLoginUserData(CusID);
                return userData.CompanyID;
            }
        }

        /// <summary>
        /// 登陆数据缓存Key
        /// </summary>
        public string CacheUserkey(int cusID = 0)
        {
            string key = "kmer:cache:LOGIN_USER_DATA:";
            if (cusID > 0)
            {
                return key + cusID;
            }

            return key + CusID;
        }

        /// <summary>
        /// 缓存的用户数据
        /// </summary>
        public LoginUserData CacheLoginUserData(int cusID = 0)
        {
            var loginUserData = new LoginUserData();
            var userkey = CacheUserkey(cusID);
            if (RedisCache.Exists(userkey))
            {
                loginUserData = RedisCache.Get<LoginUserData>(userkey);
            }
            return loginUserData;
        }

        /// <summary>
        /// 缓存登陆数据
        /// </summary>
        /// <param name="loginUserData"></param>
        public void SetCacheLoginUserData(LoginUserData loginUserData)
        {
            RedisCache.AddObject(CacheUserkey(loginUserData.CusID), loginUserData, Timeout);
        }

        /// <summary>
        /// 检查用户信息
        /// </summary>
        private static int CheckUserToken(HttpRequest Request, ApiConfig api)
        {
            var userToken = Request.Get("u", "");
            if (string.IsNullOrWhiteSpace(userToken)) return 0;
            string key = USERTOKEN_KEY + userToken;
            if (!RedisCache.Exists(key) && !existsRedis(key))
            {
                string msg = $"用户Token已经过期 {userToken}";
                Log.Error(msg, "UserToken");
                return 0;
            }
            if (userToken.StartsWith("A:"))
            {
                //string UserId = RedisCache.Get(userToken);
                AdminUserFactory.Instance.CheckUserAccessToken(key);
                return 0;
            }
            if (userToken.StartsWith("N:"))
            {
                //string UserId = RedisCache.Get(userToken);
                string userName = RedisCache.GetString(key);
                if (string.IsNullOrWhiteSpace(userName))
                    return 0;
                //UserInfo.CusName = userName;
                //UserInfo.AnonymousId = userToken;
                return 0;
            }
            var cusId = 0;
            try
            {
                cusId = RedisCache.GetInt(key, 0);
                //if (!myCache.Exists(userToken)) return;
                var userFactory = FactoryMaker.Get<IUserFactory>("user-facotry", "com.kmer.db.MemberShipFactory,com.kmer.db");
                var user = userFactory.GetUserByUserID(cusId);
                if (user == null) return 0;
                RedisCache.Expire(key, Timeout);

                //未实现DoLogin方法,暂屏蔽
                //userFactory.DoLogin(user);

                //var dc = new km_platformEntities();
                //if (dc.YhChatPhoneOsTypes.Any(i => i.CusId == user.CusId && i.OSType == api.OsType)) return;
                //dc.YhChatPhoneOsTypes.Add(new yh_chatPhoneOsType() {
                //	CusId = user.CusId,
                //	OSType = api.OsType,
                //	CreateDate = DateTime.Now
                //});
                //try {
                //	dc.SaveChanges();
                //} catch (Exception ex) {
                //	Log.Error(ex);
                //}
            }
            catch (Exception ex)
            {
                Log.Error(ex);
            }
            return cusId;
        }

        /// <summary>
        /// 检查Token
        /// </summary>
        /// <param name="thisType"></param>
        /// <param name="r"></param>
        /// <param name="isOutput">是否输出错误信息</param>
        /// <returns> Token 无效 返回false</returns>
        protected bool CheckAccessToken(Type thisType, out object r, bool isOutput = true)
        {
            r = null;
            if (thisType == typeof(TokenHandler) || this.Controller == "Debuger") return true;
            if (string.Compare("GetDTD", this.Action, StringComparison.OrdinalIgnoreCase) == 0)
                return true;

            //if (string.IsNullOrWhiteSpace(token) && Session != null) {
            //	if (Session["token"] != null)
            //		token = Session["token"].ToString();
            //}
            //ApiApp = myCache.Get(token, "").FromJson<yhAPIApp>();
            try
            {
                var token = Request.Get("token", "");
                if (!string.IsNullOrEmpty(token))
                {
                    ApiApp = RedisCache.GetAndDecodeJson<ApiConfig>(token);
                    if (ApiApp != null)
                    {
                        Token = token;
                        return true;
                    }
                    else
                    {
                        r = this.Error("token" + token + "无效", 4001);
                    }
                }
                if (isOutput)
                    output(r);
                return false;
            }
            catch (Exception ex)
            {
                Log.Error(ex);
                r = this.Error(ex.Message, 4001);
                if (isOutput)
                    output(r);
                return false;
            }
        }

        /// <summary>
        /// 把API的调用记录写到 Redis中
        /// </summary>
        /// <param name="parameters"></param>
        /// <param name="beginTime"></param>
        /// <param name="r"></param>
        protected void AddApiCallLog(string parameters, DateTime beginTime, object r)
        {
            var apiLog = new ApiLog()
            {
                Controller = this.Controller,
                Action = this.Action,
                CusID = this.CusID,
                IpAddress = Request.GetClientIpAddress(),
                BeginTime = beginTime,
                EndTime = DateTime.Now,
                Params = parameters,
            };
            if (ApiApp != null)
            {
                apiLog.AppName = ApiApp.AppName;
                apiLog.AppID = ApiApp.ID;
            }
            ;
            var ar = (ApiResult)r;
            if (r != null)
            {
                apiLog.IsSuccess = ar.Success;
                apiLog.ErrorCode = ar.Code;
                apiLog.Message = ar.Message;
            }
            //if (!Request.IsLocal) {
            //	Task.Run(() => ApiLog.SaveAsync(apiLog));
            //}
        }
        /// <summary>
        /// 返回JSON
        /// </summary>
        /// <param name="r"></param>
        void output(object r)
        {
            SetHeader(Response);
            Response.AddHeader("Content-Type", "application/json");
            Response.Write(r.ToJson());
        }
        internal static void SetHeader(HttpResponse Response)
        {
            Response.ClearHeaders();
            Response.AddHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With,Content-Type,Accept,Access-Control-Request-Method,X_FILENAME");
            Response.AddHeader("Access-Control-Allow-Methods", "GET,PUT,POST,HEAD,DELETE,OPTIONS");
            Response.AddHeader("Access-Control-Max-Age", "360000");
            Response.AddHeader("Access-Control-Allow-Credentials", "true");
            Response.AddHeader("Access-Control-Allow-Origin", "*");
        }
        /// <summary>
        /// 日志
        /// </summary>
        /// <param name="beginTime"></param>
        /// <param name="isError"></param>
        private void log(DateTime beginTime, bool isError)
        {
            var endTime = DateTime.Now;
            var st = endTime - beginTime;
            var ip = Request.GetClientIpAddress();
            if (isError)
            {
                Log.Error("{6}\n{3}\n执行API（{4}--{5}）错误：\n{0}-{1}\n{2}", "API",
                    beginTime, endTime, st, ip,
                    this.Controller,
                    this.Action,
                    this.ApiApp != null ? this.ApiApp.AppName : "NNNN");
            }
            //因为已经在Redis中记录了每个API的执行情况，所以这里就只记录错误信息
            // else {
            //	Log.WriteLog("{3}\n执行API（{4}--{5}）成功：\n{0}-{1}\n{2}", "API",
            //		Log.LogType.INFO, beginTime, endTime, st, ip,
            //		this.Controller,
            //		this.Action);
            //}
        }
        /// <summary>
        /// 处理方法
        /// </summary>
        /// <param name="path"></param>
        /// <param name="parameters"></param>
        /// <param name="UserID"></param>
        /// <returns></returns>
        protected object parseMethod(string path, string parameters, string UserID)
        {
            object result = null;
            var action = string.IsNullOrWhiteSpace(path)
                ? Request.Get("a", string.Empty)
                : path.Split('/').Distinct().FirstOrDefault(item => string.IsNullOrWhiteSpace(item) == false);
            if (string.IsNullOrWhiteSpace(action))
                return Error("没有Action参数", 404);

            var type = GetType();
            var paramType = 1;
            if (Request.Headers.AllKeys.Contains("Caller"))
            {
                if (Request.Headers["Caller"] == "kmerApiSDK")
                {
                    paramType = 2;
                }
            }
            var ms = type.GetMethods();
            var m = ms.FirstOrDefault(item => string.CompareOrdinal(item.Name, action) == 0);
            if (m == null) return Error("没有此Action：" + action, 404);
            this.Action = m.Name;
            var attribs = m.GetCustomAttributes(false);
            var isAutoCovrtFromJSon = attribs.Any(item => item is JsonTypeAttribute);
            var isPassJson = attribs.Any(item => item is JSONDataAttribute);
            var isMustLogin = attribs.Any(item => item is MustLoginAttribute);
            var isMustAdmin = attribs.Any(item => item is MustAdminAttribute);
            var isMustBackend = attribs.Any(item => item is MustBackendAttribute);

            if (isMustAdmin && (string.IsNullOrWhiteSpace(UserID) || MustAdminAttribute.Check(UserID) == false))
            {
                return Error("必须是管理员", 403);
            }
            if (isMustBackend && string.IsNullOrWhiteSpace(UserID))
            {
                return Error("必须是后台用户", 403);
            }
            if (isMustBackend)
            {
                if (RcHelper.HasRights(UserID, this.Controller, m.Name) == false)
                {
                    return Error("没有权限", 405);
                }
            }
            if (isMustLogin && string.IsNullOrWhiteSpace(UserID))
            {
                Log.WriteLines(
                    "执行该操作必须登录",
                    Request.QueryString.GetQuery()
                    );
                return Error("执行该操作必须登录", 4001);
            }

            //var attr = (MustRights)attribs.FirstOrDefault(item => item is MustRights);
            //if (attr != null && attr.Check(UserInfo.StaffNo) == false) {
            //	return Error("没有权限", 405);
            //}
            //var actionRole = (RoleBcActionAttribute)attribs.FirstOrDefault(item => item is RoleBcAttribute);
            //if (actionRole != null) {
            //	if (!actionRole.CheckAction(UserInfo.StaffNo, this.Controller, action)) {
            //		return Error("没有权限", 405);
            //	}
            //}
            var api需要的参数 = m.GetParameters();
            if (isAutoCovrtFromJSon)
            {
                if (string.IsNullOrWhiteSpace(parameters) || string.CompareOrdinal(parameters.Trim(), "null") == 0)
                {
                    return Error("该API需要输入数据，但是没有检测到数据", 400);
                }
                if (api需要的参数.Length != 1)
                {
                    throw new ArgumentException(m.Name + " 方法没有输入参数（指定了JsonTypeAttribute的方法只接收一个支持反序列化JSON的对象参数）");
                }
                //var jta = (JsonTypeAttribute)attribs.FirstOrDefault(item => item is JsonTypeAttribute);
                //var param = type == 2 ? GetData<InitParam>(jsonData) : QueryStringHelper.ParseQuery<InitParam>(jsonData);
                var o = JsonTypeAttribute.Parse(parameters, api需要的参数[0].ParameterType, paramType);
                result = m.Invoke(this, new object[] { o });
            }
            else if (isPassJson)
            {
                //API需要JSON格式的参数
                if (string.IsNullOrWhiteSpace(parameters) || string.CompareOrdinal(parameters.Trim(), "null") == 0)
                {
                    return Error("该API需要输入数据，但是没有检测到数据", 400);
                }
                if (api需要的参数.Length == 0)
                {
                    throw new ArgumentException(m.Name + " 方法没有输入参数（指定了JSONDataAttribute的方法只接收一个String类型参数）");
                }
                //if (ps.Length > 1) {
                //	throw new ArgumentException(m.Name + " 方法定义了多个参数（指定了JSONDataAttribute的方法只接收一个String类型参数）");
                //}
                if (api需要的参数[0].ParameterType != typeof(string))
                {
                    throw new ArgumentException(m.Name + " 方法定义的参数不合法（指定了JSONDataAttribute的方法只接收一个String类型参数）");
                }
                //直接把string类型的参数值传入API，API自己解析
                result = m.Invoke(this, new object[] { parameters, paramType });
            }
            else
            {
                var 准备传递给api的参数 = new ArrayList();
                if (api需要的参数.Length == 0)
                {
                    result = m.Invoke(this, null);
                }
                else
                {
                    var 客户传送过来的参数 = paramType == 2
                    ? parseParam(parameters)
                    : QueryStringHelper.ParseQuery(parameters);

                    foreach (var p in api需要的参数)
                    {
                        if (p.ParameterType.IsAssignableFrom(typeof(IList<int>))
                            && (客户传送过来的参数.AllKeys.Contains(p.Name) || 客户传送过来的参数.AllKeys.Contains(p.Name + "[]")))
                        {
                            var values = 客户传送过来的参数[p.Name + "[]"] ?? 客户传送过来的参数[p.Name];
                            var ids = new List<int>();
                            foreach (var v in values.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                            {
                                var i = 0;
                                if (int.TryParse(v, out i))
                                {
                                    ids.Add(i);
                                }
                            }
                            准备传递给api的参数.Add(ids);
                        }
                        else if (p.ParameterType.IsAssignableFrom(typeof(IList<string>))
                          && (客户传送过来的参数.AllKeys.Contains(p.Name) || 客户传送过来的参数.AllKeys.Contains(p.Name + "[]")))
                        {
                            var values = 客户传送过来的参数[p.Name + "[]"] ?? 客户传送过来的参数[p.Name];
                            var lines = values.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                            准备传递给api的参数.Add(lines);

                        }
                        else if (客户传送过来的参数.AllKeys.Contains(p.Name))
                        {
                            //转换参数值
                            var converter = TypeDescriptor.GetConverter(p.ParameterType);
                            if (!converter.CanConvertFrom(typeof(string))) continue;
                            var o = converter.ConvertFrom(客户传送过来的参数[p.Name]);
                            if (o != null)
                            {
                                准备传递给api的参数.Add(o);
                            }
                        }
                        else if (p.IsOptional)
                        {
                            //可选参数使用默认值
                            //处理 DateTime
                            if (p.ParameterType == typeof(DateTime))
                            {
                                准备传递给api的参数.Add(default(DateTime));
                            }
                            else
                            {
                                准备传递给api的参数.Add(p.DefaultValue ?? p.RawDefaultValue);
                            }
                        }
                        else
                        {
                            //即不是可选参数又没有传送过来，报错
                            throw new ArgumentException(p.Name);
                        }
                    }
                    result = m.Invoke(this, 准备传递给api的参数.ToArray());
                }
            }
            return result;
        }
        /// <summary>
        /// 当前的API动作
        /// </summary>
        public string Action { get; set; }
        /// <summary>
        /// 返回数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <returns></returns>
        protected static T GetData<T>(string data)
        {
            return data.FromJson<T>();
        }
        /// <summary>
        /// 处理参数
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        protected NameValueCollection parseParam(string str)
        {
            var nv = new NameValueCollection();
            if (string.IsNullOrWhiteSpace(str))
            {
                Log.Error("解析参数失败！没有数据");
                return nv;
            }
            try
            {
                //var r = JsonConvert.DeserializeObject<Dictionary<string, object>>(str);
                var r = str.FromJson<Dictionary<string, object>>();
                foreach (var key in r.Keys)
                {
                    var o = r[key];
                    if (o is Newtonsoft.Json.Linq.JArray)
                    {
                        var arr = o as JArray;
                        var arrL = new ArrayList();
                        foreach (var item in arr)
                        {
                            arrL.Add(item);
                        }
                        nv.Add(key, arrL.Join(","));
                    }
                    else
                    {
                        nv.Add(key, r[key].ToString());
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex);
            }
            return nv;
        }
        /// <summary>
        /// Action执行车成功请调用此方法返回数据
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        protected ApiResult Success(object obj)
        {
            return new ApiResult()
            {
                Success = true,
                Data = obj
            };
        }
        /// <summary>
        /// 执行Action时发生错误请调用此方法
        /// </summary>
        /// <param name="Message"></param>
        /// <param name="code"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        protected ApiResult Error(string Message, int code = -1, object data = null)
        {
            //Log.Error("执行API发生错误:{0}\n{1}", "API", Message, code);
            var ip = Request.GetClientIpAddress();
            Log.Error("{0}--{1}\n执行API（{2}.{3}）错误：\n{4}-{5}", "API",
                    ip, this.ApiApp != null ? this.ApiApp.AppName : "NNNN",
                    this.Controller, this.Action,
                    Message, code
                    );
            return new ApiResult()
            {
                Success = false,
                Code = code,
                Message = Message,
                Data = data
            };
        }
        /// <summary>
        /// 未开发完成的API返回的错误信息
        /// </summary>
        /// <returns></returns>
        protected ApiResult NotDoneError()
        {
            return Error("革命尚未成功");
        }
        /// <summary>
        /// 执行Action时发生错误请调用此方法
        /// </summary>
        /// <param name="exp"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        protected ApiResult Error(Exception exp, int code = 0)
        {
            var exception = exp as DbEntityValidationException;
            var ip = Request.GetClientIpAddress();
            if (exception != null)
            {
                var sb = new StringBuilder();
                var dbvex = exception;
                foreach (var error in dbvex.EntityValidationErrors.Where(err => err.IsValid == false).SelectMany(err => err.ValidationErrors))
                {
                    sb.AppendFormat("{0}:{1}\r\n", error.PropertyName, error.ErrorMessage);
                }
                //Log.Error("执行API发生错误:{0}\n{1}\n{2}", "API", exp.Message, exp, sb);
                Log.Error("{0}--{1}\r\n执行API（{2}.{3}）错误：\r\n{4}-{5}\r\n{6}", "API",
                        ip, this.ApiApp != null ? this.ApiApp.AppName : "NNNN",
                        this.Controller, this.Action,
                        exp.Message, code, sb
                        );
            }
            else
            {
                //Log.Error("执行API发生错误:{0}\n{1}", "API", exp.Message, exp);
                Log.Error("{0}--{1}\r\n执行API（{2}.{3}）错误：\r\n{4}-{5}\r\n{6}\r\n{7}", "API",
                        ip, this.ApiApp != null ? this.ApiApp.AppName : "NNNN",
                        this.Controller, this.Action,
                        exp.Message, code,
                        exp.ToString(),
                        exp.StackTrace
                        );
            }

            if (Request.IsLocal)
                return new ApiResult()
                {
                    Success = false,
                    Code = code,
                    Message = exp.Message,
                    ExtMsg = exp.ToString()
                };
            return new ApiResult()
            {
                Success = false,
                Code = code,
                Message = exp.Message
            };
        }
        /// <summary>
        /// 获取当前控制器的所有API信息（不包括GetDTD）
        /// </summary>
        /// <param name="Action"></param>
        /// <param name="Key"></param>
        /// <returns></returns>
        // ReSharper disable once InconsistentNaming
        public ApiResult GetDTD(string Action = "", string Key = "")
        {
            if (Action == "Search")
            {
                return SearchApi(Key);
            }
            var type = GetType();
            var ms = type.GetMethods();
            Action = this.Request.Get("action", Action);
            if (string.IsNullOrWhiteSpace(Action))
            {
                var apiList = ms.Where(item =>
                    item.ReturnType == typeof(ApiResult) &&
                    string.CompareOrdinal(item.Name, "GetDTD") != 0);
                return Success(apiList
                    .OrderBy(m => m.Name)
                    .Select(m => GetApiInfo(this.GetType(), m, false)).ToArray());
            }
            var a = ms.FirstOrDefault(item =>
                item.Name == Action &&
                item.ReturnType == typeof(ApiResult) &&
                string.CompareOrdinal(item.Name, "GetDTD") != 0);
            return a == null
                ? Error("找不到指定的 Action（" + Action + "）", 404)
                : Success(GetApiInfo(this.GetType(), a, true));
        }
        private ApiResult SearchApi(string Key)
        {
            var cacheKey = "all-api-list";
            var allApiList = myCache.Get<IList<string>>(cacheKey);
            if (!allApiList.Any() || !myCache.Exists(cacheKey))
            {

            }
            return Success(allApiList.Contains(Key));
        }
        private int type = 0;
        /// <summary>
        /// 是否後臺方法
        /// </summary>
        public bool IsBackend
        {
            get
            {
                if (type > 0)
                {
                    return type == 1;
                }
                type = 2;
                if (checkBackend(this.GetType()))
                {
                    type = 1;
                    return true;
                }
                var ms = GetType().GetMethods();

                var apiList = ms.Where(item =>
                    item.ReturnType == typeof(ApiResult) &&
                    string.CompareOrdinal(item.Name, "GetDTD") != 0);
                if (apiList.Where(checkBackend).Any())
                {
                    type = 1;
                    return true;
                }
                return false;
            }
        }
        static bool checkBackend(Type type)
        {
            var attribs = type.GetCustomAttributes(false);
            var isMustAdmin = attribs.Any(item => item is MustAdminAttribute);
            var isMustBackend = attribs.Any(item => item is MustBackendAttribute);
            return isMustAdmin || isMustBackend;
        }
        static bool checkBackend(MethodInfo api)
        {
            var attribs = api.GetCustomAttributes(false);
            var isMustAdmin = attribs.Any(item => item is MustAdminAttribute);
            var isMustBackend = attribs.Any(item => item is MustBackendAttribute);
            return isMustAdmin || isMustBackend;
        }
        #region 解析类型
        /// <summary>
        /// 获取Type的定义
        /// </summary>
        /// <param name="type"></param>
        /// <param name="dp"></param>
        /// <returns></returns>
        static object GetTypeDtd(Type type, int dp = 0)
        {
            if (dp > 9) return null;
            var properties = type.GetProperties();
            var hashTable = new Hashtable();
            foreach (var p in properties)
            {
                var ignore = p.IsDefined(typeof(JsonIgnoreAttribute));
                if (ignore) continue;
                var t = p.PropertyType;

                var pd = p.GetCustomAttribute<ParamDescriptionAttribute>();
                var description = "";
                object defaultValue = null;
                if (pd != null)
                {
                    description = pd.Description;
                    defaultValue = pd.DefaultValue;
                }
                else
                {
                    var desc = (DescriptionAttribute)p.GetCustomAttribute(typeof(DescriptionAttribute));
                    description = desc?.Description;
                }
                var tpmHashTable = new Hashtable();
                ParseType(p.Name, t, tpmHashTable, dp);
                var fullName = string.Format("{0}({1})", p.Name, t.Name);
                if (string.IsNullOrWhiteSpace(description))
                {
                    if (tpmHashTable.ContainsKey(p.Name))
                    {
                        hashTable.Add(p.Name, tpmHashTable[p.Name]);
                    }
                    else
                    {
                        hashTable.Add(fullName, tpmHashTable[fullName]);
                    }
                }
                else
                {
                    if (tpmHashTable.ContainsKey(p.Name))
                    {
                        hashTable.Add(p.Name, new
                        {
                            类型 = tpmHashTable[p.Name],
                            说明 = description,
                            默认值 = defaultValue,
                        });
                    }
                    else
                    {
                        hashTable.Add(fullName, new
                        {
                            类型 = tpmHashTable[fullName],
                            说明 = description,
                            默认值 = defaultValue,
                        });
                    }
                }
            }
            if (hashTable.Count == 0) return type;
            return hashTable;
        }

        static void ParseType(string vName, Type t, IDictionary hashTable, int dp)
        {
            while (true)
            {
                if (t == typeof(string))
                {
                    //hashTable.Add(vName, new {
                    //	type = "String"
                    //});
                    hashTable.Add(vName, "String");
                }
                else if (t == typeof(int))
                {
                    //hashTable.Add(vName, new {
                    //	type = "Int"
                    //});
                    hashTable.Add(vName, "Int");
                }
                else if (t == typeof(short))
                {
                    //hashTable.Add(vName, new {
                    //	type = "Int"
                    //});
                    hashTable.Add(vName, "Short = Int(16)");
                }
                else if (t == typeof(long))
                {
                    //hashTable.Add(vName, new {
                    //	type = "Int"
                    //});
                    hashTable.Add(vName, "Long = Int(64)");
                }
                else if (t == typeof(float))
                {
                    //hashTable.Add(vName, new {
                    //	type = "Int"
                    //});
                    hashTable.Add(vName, "Float");
                }
                else if (t == typeof(double))
                {
                    //hashTable.Add(vName, new {
                    //	type = "Int"
                    //});
                    hashTable.Add(vName, "Double");
                }
                else if (t == typeof(decimal))
                {
                    //hashTable.Add(vName, new {
                    //	type = "Decimal"
                    //});
                    hashTable.Add(vName, "Decimal");
                }
                else if (t == typeof(bool))
                {
                    //hashTable.Add(vName, new {
                    //	type = "Boolean"
                    //});
                    hashTable.Add(vName, "Boolean");
                }
                else if (t == typeof(DateTime))
                {
                    //hashTable.Add(vName, new {
                    //	type = "DateTime"
                    //});
                    hashTable.Add(vName, "DateTime");
                }
                else if (t == typeof(Guid))
                {
                    hashTable.Add(vName, "GUID");
                }
                else if (t == typeof(IList<int>) || t == typeof(List<int>))
                {
                    hashTable.Add(vName, "List<int>");
                }
                else if (t == typeof(IList<string>) || t == typeof(List<string>))
                {
                    hashTable.Add(vName, "List<string>");
                }
                else if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    t = Nullable.GetUnderlyingType(t);
                    continue;
                    //} else if (t.IsGenericType) {
                    //    var args = t.GetGenericArguments();
                    //    if (args.Length == 1) {
                    //        hashTable.Add(vName, $"List<{args[0].Name}>");
                    //    } else if (args.Length == 2) {
                    //        hashTable.Add(vName, $"Dict<{args[0].Name}>={args[1].Name}");
                    //    } else {
                    //        hashTable.Add(string.Format("{0}({1})", vName, t.Name), GetTypeDtd(t, dp + 1));
                    //    }
                }
                else if (t.IsEnum)
                {
                    hashTable.Add(vName, "Int");
                }
                else
                {
                    hashTable.Add(string.Format("{0}({1})", vName, t.Name), GetTypeDtd(t, dp + 1));
                }
                break;
            }
        }

        /// <summary>
        /// 获取Type的定义
        /// </summary>
        /// <param name="type"></param>
        /// <param name="dp"></param>
        /// <returns></returns>
        static object GetReturnTypeDtd(ReturnTypeAttribute type, int dp = 0)
        {
            var r = GetTypeDtd(typeof(ApiResult));
            if (type == null) return r;
            var ht = (Hashtable)r;
            ht.Remove("Data(Object)");

            var hashTable = new Hashtable();
            var t = type.ReturnType;
            var pName = t.FullName;
            ParseType(pName, t, hashTable, 0);

            if (hashTable.ContainsKey(pName))
            {
                ht.Add("Data", new
                {
                    类型 = hashTable[pName],
                    说明 = type.Description

                });
            }
            else
            {
                ht.Add(string.Format("Data({0})", type.ReturnType.Name),
                    new
                    {
                        类型 = hashTable[string.Format("{0}({1})", pName, t.Name)],
                        说明 = type.Description
                    }
                );
            }
            return ht;
        }

        private static object GetParameterTypeDtd(ParameterInfo p)
        {
            var pd = p.GetCustomAttribute<ParamDescriptionAttribute>();
            var description = "";
            //object defaultValue = null;
            if (pd != null)
            {
                description = pd.Description;
                //defaultValue = pd.DefaultValue;
            }
            else
            {
                var desc = (DescriptionAttribute)p.GetCustomAttribute(typeof(DescriptionAttribute));
                description = desc?.Description;
            }
            var hashTable = new Hashtable();
            var type = p.ParameterType;
            var pName = type.FullName;
            ParseType(pName, type, hashTable, 0);
            if (p.IsOptional)
            {
                return new
                {
                    名称 = p.Name,
                    是否可选 = p.IsOptional,
                    默认值 = (p.ParameterType == typeof(DateTime))
                        ? default(DateTime)
                        : p.DefaultValue,
                    类型 = hashTable.ContainsKey(pName)
                        ? hashTable[pName]
                        : hashTable[$"{pName}({type.Name})"],
                    说明 = description
                };
            }
            return new
            {
                名称 = p.Name,
                是否可选 = false,
                类型 = hashTable.ContainsKey(pName)
                        ? hashTable[pName]
                        : hashTable[$"{pName}({type.Name})"],
                说明 = description
            };
        }
        /// <summary>
        /// 获取Type的定义
        /// </summary>
        /// <param name="type"></param>
        /// <param name="dp"></param>
        /// <returns></returns>
        static object[] GetInputParamTypeDtd(Type type, int dp = 0)
        {
            if (type == null || dp > 9) return null;
            var properties = type.GetProperties();
            var arrayList = new ArrayList();
            foreach (var p in properties)
            {
                var t = p.PropertyType;
                //if (BlockParamNames.Contains(p.Name))
                //    continue;
                var pd = p.GetCustomAttribute<ParamDescriptionAttribute>(false);
                var description = p.GetCustomAttribute<DescriptionAttribute>(false);
                var jsonProperty = p.GetCustomAttribute<JsonPropertyAttribute>(false);

                var varType = t.Name;
                if (varType == "List`1" || varType == "IList`1")
                {
                    if (t == typeof(IList<int>) || t == typeof(List<int>))
                    {
                        varType = "List<Int>";
                    }
                    else if (t == typeof(IList<string>) || t == typeof(List<string>))
                    {
                        varType = "List<string>";
                    }
                }
                var pName = jsonProperty == null
                    ? p.Name
                    : (string.IsNullOrWhiteSpace(jsonProperty.PropertyName) ? p.Name : jsonProperty.PropertyName);
                var oDefalutValue = pd?.DefaultValue;
                if (pd == null)
                {
                    arrayList.Add(new
                    {
                        名称 = pName,
                        类型 = varType,
                        说明 = description?.Description,
                        是否可选 = (jsonProperty != null) && (jsonProperty.Required != Required.Always)
                    });
                }
                else
                {
                    arrayList.Add(new
                    {
                        名称 = pName,
                        类型 = varType,
                        说明 = pd.Description,
                        默认值 = oDefalutValue,
                        是否可选 = (jsonProperty != null) && (jsonProperty.Required != Required.Always)
                    });
                }
            }
            if (arrayList.Count == 0) return null;
            return arrayList.ToArray();
        }

        /// <summary>
        /// 获取API的定义信息
        /// </summary>
        /// <param name="ClassType"></param>
        /// <param name="api"></param>
        /// <param name="isFull"></param>
        /// <returns></returns>
        static object GetApiInfo(Type ClassType, MethodInfo api, bool isFull)
        {
            var attribs = api.GetCustomAttributes(false);
            var isMustLogin = ClassType.GetCustomAttribute<MustLoginAttribute>(true) != null || attribs.Any(item => item is MustLoginAttribute);
            var isMustAdmin = ClassType.GetCustomAttribute<MustAdminAttribute>(true) != null || attribs.Any(item => item is MustAdminAttribute);
            var isMustBackend = ClassType.GetCustomAttribute<MustBackendAttribute>(true) != null || attribs.Any(item => item is MustBackendAttribute);
            var isMustSplitPage = attribs.Any(item => item is MustSplitPageAttribute);

            var obs = api.GetCustomAttribute<ObsoleteAttribute>();
            var version = api.GetCustomAttribute<ApiVersionAttribute>();
            var returnType = (ReturnTypeAttribute)attribs.FirstOrDefault(item => item is ReturnTypeAttribute);
            var description = (DescriptionAttribute)attribs.FirstOrDefault(item => item is DescriptionAttribute);
            if (isFull)
            {
                object[] Params;
                if (attribs.Any(item => item is JsonTypeAttribute))
                {
                    Params = GetInputParamTypeDtd(api.GetParameters().FirstOrDefault()?.ParameterType);
                }
                else
                {
                    Params = api.GetParameters().Select(GetParameterTypeDtd).ToArray();
                }

                return new
                {
                    名称 = api.Name,
                    弃用 = obs == null ? null : new
                    {
                        obs.Message
                    },
                    程序集 = GetDllInfo(ClassType),
                    说明 = description == null ? "<暂无>" : description.Description,
                    版本 = version == null ? "-" : version.Vesion,
                    权限 = new
                    {
                        必须登录 = isMustLogin || isMustBackend || isMustAdmin,
                        必须管理员 = isMustAdmin,
                        必须是后台用户 = isMustBackend || isMustAdmin
                    },
                    参数 = Params,
                    支持分页 = isMustSplitPage,
                    返回值 = GetReturnTypeDtd(returnType)
                };
            }

            return new
            {
                名称 = api.Name,
                弃用 = obs == null ? null : new
                {
                    obs.Message
                },
                程序集 = GetDllInfo(ClassType),
                说明 = description == null ? "<暂无>" : description.Description,
                版本 = version == null ? "-" : version.Vesion,
                权限 = new
                {
                    必须登录 = isMustLogin || isMustBackend || isMustAdmin,
                    必须管理员 = isMustAdmin,
                    必须是后台用户 = isMustBackend || isMustAdmin
                },
                支持分页 = isMustSplitPage,
            };
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="clasType"></param>
        /// <returns></returns>
        static object GetDllInfo(Type clasType)
        {
            var ver = clasType.Assembly.GetName();
            return new
            {
                ver.Name,
                Version = ver.Version.ToString(),
                ver.FullName,
            };
        }

        #endregion
    }
    /// <summary>
    /// API统一返回结构
    /// </summary>
    public class ApiResult
    {
        /// <summary>
        /// API是否执行成功
        /// </summary>
        [ParamDescription("表示该API是否执行成功", DefaultValue = true)]
        public bool Success { get; set; }
        /// <summary>
        /// 错误代码
        /// </summary>
        [ParamDescription("错误代码，0-无错误", DefaultValue = -1)]
        public int Code { get; set; }
        /// <summary>
        /// 错误信息
        /// </summary>
        [ParamDescription("错误描述")]
        public string Message { get; set; }
        /// <summary>
        /// 扩展信息
        /// </summary>
        [ParamDescription("详细的错误信息，Debug模式下有效")]
        public string ExtMsg { get; set; }
        /// <summary>
        /// 返回数据
        /// </summary>
        [ParamDescription("该API返回的数据")]
        public object Data { get; set; }
    }
    /// <summary>
    /// 找不到符合请求的API Handler时返回这个默认Handler
    /// </summary>
    public class DefaultHandler : IHttpHandler, IReadOnlySessionState
    {
        /// <summary>
        /// 
        /// </summary>
        public bool IsReusable => false;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        public void ProcessRequest(HttpContext context)
        {
            var response = context.Response;

            BaseHandler.SetHeader(response);
            response.AddHeader("Content-Type", "application/json");
            response.Write((new
            {
                Success = false,
                Message = "没有任何API",
                Code = 404,
                Url = context.Request.RawUrl
            }).ToJson());
        }
    }
    /// <summary>
    /// 相应OPTIONS的通用API
    /// </summary>
    public class OptionsHandler : IHttpHandler, IReadOnlySessionState
    {
        /// <summary>
        /// 
        /// </summary>
        public bool IsReusable => false;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        public void ProcessRequest(HttpContext context)
        {
            var response = context.Response;

            BaseHandler.SetHeader(response);
            response.AddHeader("Content-Type", "application/json");
            response.Write((new
            {
                Success = true,
                Message = "HELLO"
            }).ToJson());
        }
    }
    /// <summary>
    /// App配置信息
    /// </summary>
    public class ApiConfig
    {
        /// <summary>
        /// ID
        /// </summary>
        public Guid ID { get; set; }

        /// <summary>
        /// App名称
        /// </summary>
        public string AppName { get; set; }

        /// <summary>
        /// App密钥
        /// </summary>
        public string AppSecret { get; set; }

        /// <summary>
        /// App类型
        /// </summary>
        public int AppType { get; set; }
        /// <summary>
        /// 操作系统类型
        /// 1-IOS
        /// 2-安卓
        /// 3-WP
        /// </summary>
        public int OsType { get; set; }
    }
}
